/**
 * The Interface class will get the user input, generates and send a message object to MessagePasser of the parent.
 */

package core;

import java.util.*;
import java.sql.Timestamp;
import common.*;

public class Interface extends Thread{
	private Node parent;
	private boolean running;
	
	private Scanner key_in;
	
	public Interface( Node _parent ){
		parent = _parent;
		key_in = new Scanner( System.in );
		turnoff();	// prevent the screen from getting swamped by prompts
	}
	
	/**
	 * Thread core: This does receive string input from the user, parse the input, and trigger the requested task or send a message 
	 */
	public void run(){
		while( running ){
			// prompt
			System.out.print( Utils.ipToString( parent.get_ip() ) + ": " + parent.get_pid() + ":" + "$ " );
			
			// receive input
			String input = key_in.nextLine();
			StringTokenizer input_tokens = new StringTokenizer( input );
						
			// input handling
			if( input_tokens.hasMoreTokens() ){		// check: 1st token
				String command = null;
				
				boolean msg_created = false;
				int msg_type = Def.NOT_ASSIGNED;
				int msg_rpid = Def.NOT_ASSIGNED;
				long msg_rip = Def.NOT_ASSIGNED;
				String msg_arg1 = null;
				String msg_arg2 = null;
				
				// decide the type of command
				command = input_tokens.nextToken();		// copy: 1st token
				command = command.trim();
				if( command.toLowerCase().equals( "help" ) ){
					System.out.println( "\n-shell: [ HELP :: Message Rules ]" );
					System.out.println( "$ ls  --  show the list of local files" );
					System.out.println( "$ ls (pid)  --  show the list of remote files on (id)" );
					System.out.println( "$ say (pid) (msg)  --  send a message" );
					
					System.out.println( "$ kill (pid)  --  kill a process" );
					System.out.println( "$ terminate  --  terminate the entire programs" );
					
					//System.out.println( "$ disconnect (pid)  --  disconnect the connection between me and (id)" );
					//System.out.println( "$ quit  --  terminate the process" );
					
					System.out.println();
					
				}else if( command.toLowerCase().equals( "say" ) ){
					msg_type = Def.MSG;

				}else if( command.toLowerCase().equals( "terminate" ) ){
					msg_type = Def.TERMINATE;
				}else{
					System.out.println( "-shell: " + command + ": command not found" );
				}
				
				
				// decide the receiver
				if( msg_type != Def.NOT_ASSIGNED ){
					if( input_tokens.hasMoreTokens() ){		// check: 2nd token
						String temp = input_tokens.nextToken();		// copy: 2nd token
						//Utils.print_log( temp );
						
						if( Utils.isNumber( temp ) ){
							msg_rpid = Integer.parseInt( temp );
							//Utils.print_log( temp );
							
							// need to check the routing table, if the receiver exists
							if( msg_rpid != Def.BROADCAST )
								msg_rip = parent.get_router().ip_lookup( msg_rpid );
						}
					}
					
					if( msg_rpid == Def.NOT_ASSIGNED ){	// if it still doesn't have the receiver's id,
						System.out.println( "-shell: " + command + " needs (receiver_ID) as a parameter (type HELP for more instruction)" );
					}
				}//end-of-if( msg_type != Def.NOT_ASSIGNED )
				
				// decide the msg contents
				if( msg_type == Def.MSG ){
					if( input_tokens.hasMoreTokens() ){			// check: 3rd token
						msg_arg1 = input_tokens.nextToken();
						msg_arg2 = "";
						msg_created = true;	// MSG must have 3 paramesters
					}else
						System.out.println( "-shell: " + command + " needs (location) as a parameter (type HELP for more instruction)" );
					
				}else if( msg_type == Def.TERMINATE ){
					msg_rpid = Def.BROADCAST;
					msg_created = true;
					
				}else if( msg_type != Def.NOT_ASSIGNED && msg_rpid != Def.NOT_ASSIGNED ){
					msg_created = true;
				}//end-of-if( msg_type == Def.REQUEST_READ || msg_type == Def.REQUEST_WRITE )
				//
				// -- PARSING IS DONE -- //
				
				
				
				// -- create a MSG and send it -- //
				if( msg_created ){
					long msg_time_ms = System.currentTimeMillis();
					
					if( msg_type == Def.NOT_ASSIGNED )
						Utils.print_log( "ERROR: critical error (check your code @438uva) -- Interface.java" );
					
					{	// messages other than REQEUEST_READ || REQUEST_WRITE
						// create a msg
						Message msg = new Message( msg_type, msg_rpid, msg_rip, parent.get_pid(), parent.get_ip(),
										msg_time_ms, msg_arg1 + msg_arg2, null );
						// send the msg (1-to-1)
						parent.get_router().send( msg );
					}
					
					System.out.println( "-shell: your message is sent" );
					
				}//end-of-if( msg_created )
			}//end-of-if( input_tokens.hasMoreTokens() )
		}//end-of-while
	}//end-of-run()
	
	// displays the text message from the other nodes
	public void show_message( Message msg ){
		System.out.println( "-shell(" + parent.get_pid() + ":" + Utils.ipToString( parent.get_ip() ) + "): You've got a message from (" + msg.get_sender_pid() + ":" + msg.get_sender_ip() + "): \""
							+ msg.get_content() + "\" [" + new Timestamp( msg.get_timestamp() ) + "]" );
	}
	
	// These turn on/off the user interface of a node (required for simulation with multiple nodes, to make all nodes shut up but one talk). 
	public void turnoff(){ running = false; }
	public void turnon(){ running = true; start(); }
	public boolean status(){ return running; }
}//end-of-class
